package com.redstars.tool.screw.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.smallbun.screw.core.Configuration;
import cn.smallbun.screw.core.engine.EngineConfig;
import cn.smallbun.screw.core.engine.EngineFileType;
import cn.smallbun.screw.core.engine.EngineTemplateType;
import cn.smallbun.screw.core.execute.DocumentationExecute;
import cn.smallbun.screw.core.process.ProcessConfig;
import com.redstars.generate.convert.SysDatasourceConvert;
import com.redstars.generate.entity.SysDatasource;
import com.redstars.generate.exception.RedstarsException;
import com.redstars.generate.service.SysDatasourceService;
import com.redstars.generate.vo.SysDatasourceVo;
import com.redstars.tool.screw.service.ScrewService;
import com.redstars.tool.screw.utils.ServletUtils;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;

/**
 * @author : zhouhx
 * @date : 2023/3/31 10:09
 */
@Service
@Slf4j
public class ScrewServiceImpl implements ScrewService {
    private static final String FILE_OUTPUT_DIR = System.getProperty("java.io.tmpdir") + File.separator
            + "db-doc";
    private static final String DOC_FILE_NAME = "数据库文档";
    private static final String DOC_VERSION = "1.0.0";
    private static final String DOC_DESCRIPTION = "文档描述";

    @Resource
    SysDatasourceService datasourceService;

    @Override
    public void doExprotFile(String sysDatasourceId,EngineFileType fileOutType, Boolean deleteFile, HttpServletResponse response) {
        String fileName = DOC_FILE_NAME+"_"+ IdUtil.fastSimpleUUID();
        String filePath = doExprotFile(fileOutType,fileName,sysDatasourceId);
        //下载后的文件名
        String downloadFileName = DOC_FILE_NAME + fileOutType.getFileSuffix();
        try {
            // 读取，返回
            ServletUtils.writeAttachment(response, downloadFileName, FileUtil.readBytes(filePath));
        } catch (IOException e) {
            log.error("",e);
            throw new RedstarsException(e.getMessage());
        } finally {
            handleDeleteFile(deleteFile, filePath);
        }
    }

    private String doExprotFile(EngineFileType fileOutputType, String fileName,String sysDatasourceId){
        Assert.notNull(sysDatasourceId,"数据源id不能为空");
        SysDatasourceVo datasourceVo = datasourceService.detail(Long.valueOf(sysDatasourceId));
        HikariDataSource dataSource = buildDataSource(SysDatasourceConvert.INSTANCE.convert(datasourceVo));
        // 创建 screw 的配置
        Configuration config = Configuration.builder()
                .version(DOC_VERSION)
                .description(DOC_DESCRIPTION)
                .dataSource(dataSource)
                // 引擎配置
                .engineConfig(buildEngineConfig(fileOutputType, fileName))
                // 处理配置
                .produceConfig(buildProcessConfig())
                .build();
        //生成数据库文档
        new DocumentationExecute(config).execute();

        return FILE_OUTPUT_DIR + File.separator + fileName + fileOutputType.getFileSuffix();
    }
    /**
     *
     * @author zhuohx
     * @description 创建数据源
     * @parms  sysDatasource 系统数据源
     * @return com.zaxxer.hikari.HikariDataSource
     * @throws
     * @date 2023/3/31 10:25
     */
    private HikariDataSource buildDataSource(SysDatasource sysDatasource) {
        // 创建 HikariConfig 配置类
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setJdbcUrl(sysDatasource.getConnUrl());
        hikariConfig.setUsername(sysDatasource.getUsername());
        hikariConfig.setPassword(sysDatasource.getPassword());
        //获取table的注释信息
        hikariConfig.addDataSourceProperty("useInformationSchema", "true");
        // 创建数据源
        return new HikariDataSource(hikariConfig);
    }

    /**
     *
     * @author zhuohx
     * @description 创建 screw 的引擎配置
     * @parms  [fileOutputType, docFileName]
     * @return cn.smallbun.screw.core.engine.EngineConfig
     * @throws
     * @date 2023/3/31 10:35
     */
    private static EngineConfig buildEngineConfig(EngineFileType fileOutputType, String docFileName) {
        return EngineConfig.builder()
                .fileOutputDir(FILE_OUTPUT_DIR) // 生成文件路径
                .openOutputDir(false) // 打开目录
                .fileType(fileOutputType) // 文件类型
                .produceType(EngineTemplateType.freemarker) // 文件类型
                .fileName(docFileName) // 自定义文件名称
                .build();
    }

    /**
     *
     * @author zhuohx
     * @description 创建 screw 的处理配置
     * @parms  []
     * @return cn.smallbun.screw.core.process.ProcessConfig
     * @throws
     * @date 2023/3/31 10:36
     */
    private static ProcessConfig buildProcessConfig() {
        return ProcessConfig.builder()
                .ignoreTablePrefix(Arrays.asList())
                .build();
    }

    /**
     *
     * @author zhuohx
     * @description 删除文件
     * @parms  [deleteFile, filePath]
     * @return void
     * @throws
     * @date 2023/3/31 10:39
     */
    private void handleDeleteFile(Boolean deleteFile, String filePath) {
        if (!deleteFile) {
            return;
        }
        FileUtil.del(filePath);
    }
}
